package kom;

import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Transparency;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.HashMap;
import javax.imageio.ImageIO;

public class Bitmaps {

    public static String paraURL(String s) {
        StringBuilder o = new StringBuilder();
        for (char ch : s.toCharArray()) {
            if (isUnsafe(ch)) {
                o.append('%');
                o.append(toHex(ch / 16));
                o.append(toHex(ch % 16));
            } else {
                o.append(ch);
            }
        }
        return o.toString();
    }

    private static char toHex(int ch) {
        return (char) (ch < 10 ? '0' + ch : 'A' + ch - 10);
    }

    private static boolean isUnsafe(char ch) {
        if (ch > 128 || ch < 0) {
            return true;
        }
        return " %$&+,/:;=?@<>#%".indexOf(ch) >= 0;
    }
    public HashMap<Integer, BufferedImage[]> sprites = new HashMap<Integer, BufferedImage[]>();
    public HashMap<Integer, BufferedImage[]> negativeSprites = new HashMap<Integer, BufferedImage[]>();
    public HashMap<Integer, BufferedImage[]> animatedEffects = new HashMap<Integer, BufferedImage[]>();
     
    public BufferedImage[][] tiles;
    
    public int getTileIndex(BlockType b) {
         if(b == BlockType.DIRT)
             return 1;
         else if(b==BlockType.AIR)
             return 2;
         return -1;
    }
    
    // modifier is the direction of the free block face
    public BufferedImage getTileImage(BlockType b) {
        if(b == BlockType.DIRT) {
            return tiles[0][0];
        }
        if(b == BlockType.AIR) {
            return tiles[0][2];
        }
        if(b == BlockType.STONE) {
            return tiles[0][1];
        }
        return null;
    }
    
    // modifier is the direction of the free block face
    public BufferedImage getTileImage(BlockType b, int direction) {
        // -- Indexes of the variations of the tile
        //1 = down
        //2 = up
        //3 = right
        //4 = left
        int directionIndex = 1;
        if(direction==Map.DIR_UP)
            directionIndex = 2;
        else if(direction==Map.DIR_LEFT)
            directionIndex = 3;
        if(direction==Map.DIR_RIGHT)
            directionIndex = 4;
        
        // gets the variation of that tile
        if(b == BlockType.DIRT)
            return tiles[directionIndex][0];
        if(b == BlockType.AIR)
            return tiles[directionIndex][2];
        if(b == BlockType.STONE)
            return tiles[directionIndex][1];
        return null;
    }

    public void loadAll() throws IOException {
        BufferedImage src = ImageIO.read(Kom.class.getResource("/resource/tilesets/tiles.png"));
        tiles = new BufferedImage[src.getWidth()/8][src.getHeight()/8];

        // read the tiles, still in simple shape
        for (int i = 0; i < 12; i++) {
            for (int j = 0; j < 4; j++) {
                tiles[i][j] = clip(src, i * 8, j * 8, 8, 8);
            }
        }

        // automatically loading effects
        int effectCounter = 0;
        while(true) {
           BufferedImage effect;
            try {
                // reads from inside the jar so images dont need to be sent separately
                effect = ImageIO.read(Kom.class.getResource("/resource/effects/effect" + effectCounter + ".png"));
            } catch (Throwable t) {
                break;
            }
            if(effect == null)
                break;
            
            BufferedImage [] effects = new BufferedImage[effect.getWidth()/16];
            for (int x = 0; x < effect.getWidth() / 16; x++) {
                effects[x] = clip(effect, x * 16, 0, 16, 16);
            }
            animatedEffects.put(effectCounter, effects);
            effectCounter++;
        }     
        
        // automatically read sprite sheets named "sprites<number>.png" and stores it
        int spriteCounter = 0;
        while (true) {
            BufferedImage chara;
            try {
                // reads from inside the jar so images dont need to be sent separately
                chara = ImageIO.read(Kom.class.getResource("/resource/sprites/sprites" + spriteCounter + ".png"));
            } catch (Throwable t) {
                break;
            }
            if (chara == null) {
                break;
            }
            BufferedImage[] sprite = new BufferedImage[chara.getWidth() / 16];
            BufferedImage[] negateSprite = new BufferedImage[chara.getWidth() / 16];
            for (int x = 0; x < chara.getWidth() / 16; x++) {
                sprite[x] = clip(chara, x * 16, 0, 16, 20);
                negateSprite[x] = horizontalflip(clip(chara, x * 16, 0, 16, 20));
            }
            sprites.put(spriteCounter, sprite);
            // store the inverse too so we only need to send 1 image to client
            negativeSprites.put(spriteCounter, negateSprite);
            spriteCounter++;
        }
    }

    // flips the image
    public BufferedImage horizontalflip(BufferedImage bufferedImage) {

        AffineTransform tx = AffineTransform.getScaleInstance(-1, 1);
        tx.translate(-bufferedImage.getWidth(null), 0);
        AffineTransformOp op = new AffineTransformOp(tx,
                AffineTransformOp.TYPE_NEAREST_NEIGHBOR);
        bufferedImage = op.filter(bufferedImage, null);
        return bufferedImage;

    }

    public static BufferedImage clip(BufferedImage src, int x, int y, int w, int h) {
        GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
        BufferedImage newImage = null;

        try {
            GraphicsDevice screen = ge.getDefaultScreenDevice();
            GraphicsConfiguration gc = screen.getDefaultConfiguration();
            newImage = gc.createCompatibleImage(w, h, Transparency.BITMASK);
        } catch (Exception e) {
        }

        if (newImage == null) {
            newImage = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
        }

        int[] pixels = new int[w * h];
        src.getRGB(x, y, w, h, pixels, 0, w);
        newImage.setRGB(0, 0, w, h, pixels, 0, w);

        return newImage;
    }
}